<template>
  <el-form ref="form" :model="form" v-bind="mergedFormOptions" v-on="$listeners">
    <el-row v-for="(group, index) in groupItems" :key="index" :gutter="12">
      <el-col
        v-for="(item, subIndex) in group"
        :key="(item.prop || '') + subIndex"
        :span="item.span"
        :offset="item.offset || 0"
      >
        <!--  表单项用slot-->
        <slot :name="item.slot" v-bind="{ form, item }">
          <template v-if="item.type">
            <el-form-item
              :ref="'formItem_'+item.prop"
              :label="item.label"
              :prop="item.prop"
              v-bind="{ ...item.formItemAttrs }"
            >
              <component
                :is="getType(item.type)"
                v-if="item.type === 'input' && !item.noTrim"
                :ref="item.prop"
                v-model.trim="form[item.prop]"
                :item="item"
              />
              <component
                :is="getType(item.type)"
                v-else
                :ref="item.prop"
                :value.sync="form[item.prop]"
                :item="item"
              />
            </el-form-item>
          </template>
        </slot>
      </el-col>
    </el-row>
    <el-row v-if="isSearchForm">
      <div :style="{ 'text-align': searchBtnPosition}">
        <throttle-button class="query" :type="searchButton" @click="search">查询</throttle-button>
        <el-button class="reset" @click="reset">重置</el-button>
        <slot name="handle-area" />
      </div>
    </el-row>
  </el-form>
</template>

<script>
import FInput from './form-items/f-input'
import FSelect from './form-items/f-select'
import DatePicker from './form-items/date-picker'
import Cascader from './form-items/cascader'

export default {
  name: 'TpForm',
  components: {
    DatePicker,
    FSelect,
    FInput,
    Cascader
  },
  model: {
    prop: 'originData',
    event: 'change'
  },
  props: {
    searchButton: {
      type: String,
      default: 'primary'
    },
    originData: {
      type: [Object, Array],
      default: () => ({})
    },
    isSearchForm: {
      type: Boolean,
      default: false
    },
    searchBtnPosition: {
      type: String,
      default: 'left'
    },
    formItems: {
      type: Array,
      required: true
    },
    defaultForm: {
      type: Object,
      default: () => ({})
    }
  },
  data() {
    return {
      form: {},
      defaultFormData: {}
    }
  },
  computed: {
    groupItems() {
      const result = []
      let total = 0
      this.formItems.forEach(item => {
        item.span = this.getSpan(item)
        let newGroup
        if (total === 0 || (total + item.span) > 24) {
          newGroup = []
          result.push(newGroup)
        } else {
          newGroup = result[result.length - 1]
        }
        newGroup.push(item)
        total += item.span
        total = total > 24 ? item.span : total
      })
      return result
    },
    mergedFormOptions() {
      return {
        labelWidth: '85px',
        labelPosition: 'right',
        labelSuffix: '：',
        ...this.$attrs
      }
    }
  },
  watch: {
    form: {
      deep: true,
      handler(val) {
        this.$nextTick(() => {
          this.$emit('form-change', val)
          this.$emit('change', val)
        })
      }
    }
  },
  created() {
    this.form = {}
    this.initData(this.originData, true)
  },
  methods: {
    getRef(_ref, prop) {
      if (_ref === 'form') {
        return this.$refs[_ref]
      }
      if (_ref === 'formItem') {
        return this.$refs['formItem_' + prop][0]
      }
      if (_ref === 'grid.formItem') {
        return this.findChildRef('formItem', prop)
      }
      if (_ref === 'grid.formEl') {
        return this.findChildRef('formEl', prop)
      }
      if (_ref === 'formEl') {
        return this.$refs[prop][0].getRef()
      }
    },
    findChildRef(_ref, prop) {
      let ref = null
      // const arr = this.$refs.grid instanceof Array ? this.$refs.grid : [this.$refs.grid]
      for (const el of this.$refs.grid) {
        if (el) {
          ref = el.getRef(_ref, prop)
          if (ref) {
            return ref
          }
        }
      }
    },
    getSpan(item) {
      if (item.span === 'auto') {
        return null
      }
      return item.span || 6
    },
    initData(originData, isCreated) {
      if (!originData) {
        originData = this.originData
      }
      if (originData) {
        this.form = { ...originData }
        isCreated && (this.defaultFormData = { ...originData })
      }
    },
    setFormData(key, val) {
      this.$set(this.form, key, val)
    },
    search() {
      this.$emit('search', this.form)
    },
    reset() {
      this.$refs.form.resetFields()
      this.form = { ...this.getResetFormData() }
      this.$nextTick(() => {
        this.$emit('reset', this.form)
      })
    },
    getResetFormData() {
      // 兼容老逻辑
      return Object.keys(this.defaultForm).length ? this.defaultForm : this.defaultFormData
    },
    getType(type) {
      const map = {
        input: this.$options.components.FInput,
        select: this.$options.components.FSelect,
        date: this.$options.components.DatePicker,
        cascader: this.$options.components.Cascader
      }
      return map[type]
    }
  }
}
</script>

<style lang="scss" scoped></style>
